/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Tpm.h"
#include "PolicyNameHash_fp.h"

#if CC_PolicyNameHash  // Conditional expansion of this file

/*(See part 3 specification)
// Add a nameHash restriction to the policyDigest
*/
//  Return Type: TPM_RC
//      TPM_RC_CPHASH     'nameHash' has been previously set to a different value
//      TPM_RC_SIZE       'nameHash' is not the size of the digest produced by the
//                        hash algorithm associated with 'policySession'
/*
将授权值绑定到待执行命令所需要的句柄实体的名称

tpm2_policynamehash(1) - Couples a policy with names of specific objects. This is a deferred 
assertion where the hash of the names of all object handles in a TPM command is checked against the one specified in the policy.

Tpm2_policynamehash (1)-将策略与特定对象的名称耦合。这是一个延迟断言（在后面命令的执行中进行检查），
其中 TPM 命令中所有对象句柄名称的哈希值与策略中指定的哈希值进行了检查。

This command allows a policy to be bound to a specific set of TPM entities without being bound to the parameters of the command. 
This is most useful for commands such as TPM2_Duplicate() and for TPM2_PCR_Event() when the referenced PCR requires a policy.
The nameHash parameter should contain the digest of the Names associated with the handles to be used in the authorized command.
此命令允许将策略绑定到一组特定的 TPM 实体，而无需绑定到命令的参数。 这对于 TPM2_Duplicate() 和 TPM2_PCR_Event() (当引用的 PCR 需要策略时)，等命令最有用。
nameHash 参数应包含与要在授权命令中使用的句柄关联的名称的摘要。

EXAMPLE For the TPM2_Duplicate() command, two handles are provided. One is the handle of the object being duplicated 
and the other is the handle of the new parent. For that command, nameHash would contain:
nameHash ≔ HpolicyAlg(objectHandle→Name || newParentHandle→Name)
示例 对于 TPM2_Duplicate() 命令，提供了两个句柄。 一个是被复制对象的句柄，另一个是新父对象的句柄。 对于该命令，nameHash 将包含：
nameHash ≔ HpolicyAlg(objectHandle→Name || newParentHandle→Name)

If policySession→cpHash is already set, the TPM shall return TPM_RC_CPHASH. If the size of nameHash is not the size of 
policySession→policyDigest, the TPM shall return TPM_RC_SIZE.
Otherwise, policySession→cpHash is set to nameHash.
If this command completes successfully, the cpHash of the authorized command will not be used for validation. Only the 
digest of the Names associated with the handles in the command will be used.
NOTE 1 This allows the space normally used to hold policySession→cpHash to be used for policySession→nameHash instead.

如果 policySession→cpHash 已经设置，TPM 将返回 TPM_RC_CPHASH。 如果 nameHash 的大小不是 policySession→policyDigest 的大小，TPM 将返回 TPM_RC_SIZE。
否则，policySession→cpHash 被设置为 nameHash。
如果此命令成功完成，授权命令的 cpHash 将不会用于验证。 将仅使用与命令中的句柄关联的名称的摘要。
注 1 这允许通常用于保存 policySession→cpHash 的空间改为用于 policySession→nameHash。

*/
TPM_RC
TPM2_PolicyNameHash(
    PolicyNameHash_In   *in             // IN: input parameter list

    )
{
    SESSION             *session;
    TPM_CC               commandCode = TPM_CC_PolicyNameHash;
    HASH_STATE           hashState;

// Input Validation

    // Get pointer to the session structure
    session = SessionGet(in->policySession);

    // A valid nameHash must have the same size as session hash digest
    // Since the authHashAlg for a session cannot be TPM_ALG_NULL, the digest size
    // is always non-zero.
    if(in->nameHash.t.size != CryptHashGetDigestSize(session->authHashAlg))
        return TPM_RCS_SIZE + RC_PolicyNameHash_nameHash;

    // u1 in the policy session context cannot otherwise be occupied
    if(session->u1.cpHash.b.size != 0
       || session->attributes.isBound 
       || session->attributes.isCpHashDefined 
       || session->attributes.isTemplateSet)
        return TPM_RC_CPHASH;

// Internal Data Update

    // Update policy hash
    // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyNameHash || nameHash)
    //  Start hash
    CryptHashStart(&hashState, session->authHashAlg);

    //  add old digest
    CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b);

    //  add commandCode
    CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode);

    //  add nameHash
    CryptDigestUpdate2B(&hashState, &in->nameHash.b);

    //  complete the digest
    CryptHashEnd2B(&hashState, &session->u2.policyDigest.b);

    // update nameHash in session context
    session->u1.cpHash = in->nameHash;

    return TPM_RC_SUCCESS;
}

#endif // CC_PolicyNameHash